Up & Going
Chapter 1: Into Programming
get user input
1 | age = prompt( "Please tell me your age:" ); |
Converting Between Types
1 | var a = "42"; |
Scope
1 | function outer() { |
So, code inside the inner()
function has access to both variables a
and b
, but code in outer()
has access only to a
– it cannot access b
because that variable is only inside inner()
.
Chapter 2: Into JavaScript
Values & Types
- string
- number
- boolean
- null and undefined
- object
- symbol (new to ES6)
1 | a = null; |
Also, note a = undefined
. We’re explicitly setting a
to the undefined
value, but that is behaviorally no different from a variable that has no value set yet, like with the var a
; line at the top of the snippet. A variable can get to this “undefined” value state in several different ways, including functions that return no values and usage of the void operator.
array and function. But rather than being proper built-in types, these should be thought of more like subtypes – specialized versions of the object
type.
强制类型转化
1 | var a = "42"; |
1 | var a = 42; |
You should take special note of the == and === comparison rules if you’re comparing two non-primitive values, like objects (including function and array). Because those values are actually held by reference, both == and === comparisons will simply check whether the references match, not anything about the underlying values.
For example, arrays are by default coerced to strings by simply joining all the values with commas (,
) in between. You might think that two arrays with the same contents would be == equal, but they’re not:
1 | var a = [1,2,3]; |
how can all three of those comparisons be false? Because the b
value is being coerced to the “invalid number value” NaN
in the <
and >
comparisons, and the specification says that NaN
is neither greater-than nor less-than any other value.
1 | var a = 42; |
False
- “” (empty string)
- 0, -0, NaN (invalid number)
- null, undefined
- false
True
- “hello”
- 42
- true
- , [ 1, “2”, 3 ] (arrays)
- { }, { a: 42 } (objects)
- function foo() { .. } (functions)
Function Scopes
Hoisting
1 | var a = 2; |
Nested Scopes
1 |
|
Notice that c
is not available inside of bar()
, because it’s declared only inside the inner baz()
scope, and that b
is not available to foo()
for the same reason.
ES6 lets you declare variables to belong to individual blocks (pairs of { .. }
), using the let
keyword
Immediately Invoked Function Expressions (IIFEs)
1 | (function IIFE(){ |
The outer ( .. )
that surrounds the (function IIFE(){ .. })
function expression is just a nuance of JS grammar needed to prevent it from being treated as a normal function declaration.
The final ()
on the end of the expression – the })();
line – is what actually executes the function expression referenced immediately before it.
Because an IIFE is just a function, and functions create variable scope, using an IIFE in this fashion is often used to declare variables that won’t affect the surrounding code outside the IIFE:
1 | var a = 42; |
IIFEs can also have return values:
1 | var x = (function IIFE(){ |
Closure
You can think of closure as a way to “remember” and continue to access a function’s scope (its variables) even once the function has finished running.
1 | function makeAdder(x) { |
More on how this code works:
- When we call
makeAdder(1)
, we get back a reference to its inneradd(..)
that remembersx
as1
. We call this function referenceplusOne(..)
. - When we call
makeAdder(10)
, we get back another reference to its inneradd(..)
that remembersx
as10
. We call this function referenceplusTen(..)
. - When we call
plusOne(3)
, it adds3
(its innery
) to the1
(remembered byx
), and we get4
as the result. - When we call
plusTen(13)
, it adds13
(its innery
) to the10
(remembered byx
), and we get23
as the result.
this
Identifier
1 | function foo() { |
There are four rules for how this
gets set, and they’re shown in those last four lines of that snippet.
foo()
ends up settingthis
to the global object in non-strict mode – in strict mode,this
would beundefined
and you’d get an error in accessing thebar
property – so"global"
is the value found forthis.bar
.obj1.foo()
setsthis
to theobj1
object.foo.call(obj2)
setsthis
to theobj2
object.new foo()
setsthis
to a brand new empty object.
Prototypes
When you reference a property on an object, if that property doesn’t exist, JavaScript will automatically use that object’s internal prototype reference to find another object to look for the property on. You could think of this almost as a fallback if the property is missing.
The internal prototype reference linkage from one object to its fallback happens at the time the object is created. The simplest way to illustrate it is with a built-in utility called Object.create(..)
.
1 | var foo = { |
The a
property doesn’t actually exist on the bar
object, but because bar
is prototype-linked to foo
, JavaScript automatically falls back to looking for a
on the foo
object, where it’s found.
Polyfilling
ES6 defines a utility called Number.isNaN(..)
to provide an accurate non-buggy check for NaN
values
Transpiling
Here’s a quick example of transpiling. ES6 adds a feature called “default parameter values.”
1 | function foo(a = 2) { |